import os

import requests

from conf.conf import host_url
from tools.handle_data import Data
from tools.handle_loguru import logger
from tools.handle_path import cases_data_images_dir
from tools.handle_sign import HandleSign


class HandleRequests:
    def __init__(self):
        # 请求头初始化，代码已屏蔽。
        pass

    def __handle_url(self, url):
        """
        请求地址拼接，参数替换。
        1、如果url是 http:// 或  https:// 开头无需拼接；否则需进行拼接。
        2、如果url中有需要替换的字段，进行替换。
        :param url:传入的url地址（可能是完整的url地址，也可能是待拼接的url地址。）
        :return:返回新的url地址。
        """
        if url.startswith("http://") or url.startswith("https://"):
            request_url = url
        else:
            request_url = host_url + url
        logger.debug(f"处理后的url地址为：{request_url}")
        return request_url

    def __handle_headers(self):
        """
        如果Data类有token属性，那么就将token设置到请求头当中。token是按照提取规则，从响应结果提取出来，然后设置成Data类属性。
        :return:无返回值
        """
        # 1、如果Data类有token属性，那么就将token设置到请求头当中.
        if hasattr(Data, "token"):
            self.headers["Authorization"] = "Bearer {}".format(getattr(Data, "token"))
            logger.debug(f"处理后的请求头headers为：{self.headers}")
        else:
            pass

    def __handle_media_type(self, request_data):
        """
        判断请求头XN-Media-Type 是否是v3版本，是V3版本才需要去加密处理
        :param request_data: 请求数据
        :return: 更新后的请求数据
        """
        if self.headers["XN-Media-Type"] == "XN.v3":
            if hasattr(Data, "token"):
                logger.info("========= 请求头XN-Media-Type 是v3版本，且Data类中token有值，需加密处理。 =========")

                # 加密处理
                token = getattr(Data, "token")
                sign_data = HandleSign.generate_sign(token)
                request_data.update(sign_data)      # 请求体带上 timestamp + sign ；request_data为表格中请求数据的字典类型，sign_data为签名生成的字典类型。
            else:
                logger.info("========= 请求头XN-Media-Type 是v3版本，但Data类中无token值，无需加密处理。 =========")
        else:
            logger.info("=========  请求头XN-Media-Type 不是v3版本，无需加密处理。 ========= ")
        return request_data

    def send_request(self, method, url, data, file_name=None):
        """
        发请求方法
        :param method: 请求方法
        :param url: 请求地址
        :param data: 请求参数
        :param file_name: 上传的图片名(完整的文件名)，默认不上传图片。
        :return: 返回接口响应结果
        """
        try:
            new_method = method.upper()
            new_url = self.__handle_url(url=url)  # 请求地址拼接，参数替换
            self.__handle_headers()  # 请求头处理

            logger.info('======== 开始发起请求 ========')
            new_data = self.__handle_media_type(data)  # v3版本鉴权处理,为了日志输出层次清晰，把这行代码放在logger.info('请求头为:{}'.format(self.headers)) 后面

            logger.debug('请求头为:{}'.format(self.headers))
            logger.debug('请求方式:{}'.format(new_method))
            logger.debug('请求地址:{}'.format(new_url))
            logger.debug('请求参数：{}'.format(new_data))
            logger.debug('请求参数类型为：{}'.format(type(new_data)))

            if new_method == 'GET':
                if new_data:
                    response = requests.get(url=new_url, params=new_data, headers=self.headers)
                else:
                    response = requests.get(url=new_url, headers=self.headers)
                logger.debug('======== GET请求返回: {} ========'.format(response.json()))
                return response.json()

            elif new_method == 'POST':
                if file_name:
                    # 仅上传文件
                    file_path = os.path.join(cases_data_images_dir, file_name)
                    image_file = {"file": (file_name, open(file_path, "rb"), "images/git")}
                    response = requests.post(url=new_url, files=image_file)
                else:
                    # 上传文件项为空，仅发起data数据请求。
                    response = requests.post(url=new_url, json=new_data, headers=self.headers)
                logger.debug('======== POST请求返回: {} ========'.format(response.json()))
                return response.json()

            elif new_method == 'PATCH':
                response = requests.patch(url=new_url, json=new_data, headers=self.headers)
                logger.debug('======== patch请求返回: {} ========'.format(response.json()))
                return response.json()

            elif new_method == 'PUT':
                response = requests.put(url=new_url, json=new_data, headers=self.headers)
                logger.debug('======== put请求返回: {} ========'.format(response.json()))
                return response.json()

            else:
                logger.debug('======== {}请求类型暂不支持，后续再加。 ========'.format(method))
                raise AssertionError
        except Exception as e:
            logger.error('========请求发送结束，请求报错了========')
            logger.exception(e)
            raise


# 测试代码
if __name__ == '__main__':
    req_method = 'post'
    req_url = '/file/upload'
    single_case = {
        'id': 'file_upload_01',
        'title': '上传图片成功，jpg格式，小于100KB',
        'method': 'post',
        'url': '/file/upload',
        # 'files': None,
        'files': 'test_file_upload_01.jpg',
        'data': None,
        'extract_data': '{"code":"$.code","msg":"$.msg","data":"$.data"}',
        'expected_data': '{"code": "0","msg": "操作成功"}'
    }

    hr = HandleRequests()
    hr.send_request(method=single_case['method'], url=single_case['url'], data=single_case['data'], file_name=single_case['files'])
